import os

import requests
from dotenv import load_dotenv
from langchain_community.chat_models import ChatOpenAI, AzureChatOpenAI
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.embeddings import OpenAIEmbeddings, OllamaEmbeddings
from langchain_community.tools import TavilySearchResults
# pip install faiss-cpu
from langchain_community.vectorstores import FAISS
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.tools import create_retriever_tool
from langchain_ollama import OllamaLLM
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 设置USER_AGENT
os.environ['USER_AGENT'] = 'web-embedding-app/1.0'
load_dotenv()

"""创建：一个agent
维基百科: 网络不通；使用百度百科-
"""
## 1，把网页数据下载下来，然后变成向量，存到向量数据库中，然后进行相似度配了
# loader = WebBaseLoader("https://zh.wikipedia.org/wiki/%E7%8C%AB")
loader = WebBaseLoader("https://baike.baidu.com/item/%E7%8C%AB/22261")

docs = loader.load()
documents = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200
).split_documents(docs)

## 1. embeddings LLM
# 替换成本地模型
# embeddings = OllamaEmbedder(model="nomic-embed-text")
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vector = FAISS.from_documents(documents, embeddings)
## 相似度匹配，
retriever = vector.as_retriever()

retriever_tool = create_retriever_tool(
    retriever,
    "wiki_search",
    "搜索维基百科"
)
## 2. 使用LLM，需要该LLM实现：bind_tools
model = OllamaLLM(model="llama3.2:3b")
# model = ChatOpenAI(model="gpt-4")

search = TavilySearchResults(max_results=1)

## 2个工具：search-Tavily去搜，retriever_tool-维基百科
"""
为什么要用2个工具
1.猫的特征，适合用 retriever_tool-维基百科
2.今天上海天气怎么样，维基百科就不知道了，所以用 Tavily去搜
那么agent怎么知道什么时候调用什么工具呢？是大模型做的决策。
"""
tools = [search, retriever_tool]

## 获取要使用的提示
from langchain import hub

"""
hub 提示词仓库
"""
prompt = hub.pull("hwchase17/openai-functions-agent")
print(prompt.messages)

from langchain.agents import create_tool_calling_agent

##参数：model-大模型 ， tools-工具 ， prompt-提示词
##
"""
Q:使用 model = OllamaLLM(model="llama3.2:3b") This function requires a bind_tools() method be implemented on the LLM.
您好！遇到这个问题非常正常，因为 create_tool_calling_agent 是 LangChain 框架中的一个高级函数，它依赖于特定的模型具备 “函数调用”（Function Calling） 或 “工具调用”（Tool Calling） 的能力。
您本地部署的 Llama 3.2 3B 模型是一个基础模型，它本身不具备原生的工具调用能力。这个能力通常需要模型在训练时进行特殊微调，或者通过特定的提示工程来激发。
简单来说，问题不在于你的模型部署，而在于 “模型能力” 和 “LangChain函数期望” 的不匹配
替代方案：使用 ReAct 提示工程。
"""
agent = create_tool_calling_agent(model, tools, prompt)

from langchain.agents import AgentExecutor

agent_executor = AgentExecutor(agent=agent, tools=tools)

response = agent_executor.invoke({"input": "猫的特征？今天上海天气怎么样？"})
print(response)
## 猫的特征？今天上海天气怎么样？

response = agent_executor.invoke({
    "chat_history": [
        HumanMessage(content="Hi,我的名字是Cyber"),
        AIMessage(content="你好，Cyber,很高兴见到你！有什么可以帮助你的吗")
    ],
    "input":"我的名字是什么"
})
print(response)